package mx.vlabs.soapdroid.wsdl2java;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;

import mx.vlabs.soapdroid.wsdl2java.artifactbuilder.DTOArtifactBuilder;
import mx.vlabs.soapdroid.wsdl2java.artifactbuilder.EnumerationArtifactBuilder;
import mx.vlabs.soapdroid.wsdl2java.artifactbuilder.PortTypeArtifactBuilder;
import mx.vlabs.soapdroid.wsdl2java.artifactbuilder.ServiceArtifactBuilder;

import org.ow2.easywsdl.schema.api.ComplexType;
import org.ow2.easywsdl.schema.api.Element;
import org.ow2.easywsdl.schema.api.Schema;
import org.ow2.easywsdl.schema.api.SimpleType;
import org.ow2.easywsdl.schema.api.Type;
import org.ow2.easywsdl.schema.org.w3._2001.xmlschema.LocalComplexType;
import org.ow2.easywsdl.wsdl.WSDLFactory;
import org.ow2.easywsdl.wsdl.api.Description;
import org.ow2.easywsdl.wsdl.api.InterfaceType;
import org.ow2.easywsdl.wsdl.api.Service;
import org.ow2.easywsdl.wsdl.api.WSDLException;
import org.ow2.easywsdl.wsdl.api.WSDLReader;

import com.sun.crypto.provider.DESCipher;

public class Wsdl2Java {
	
	private Description description;
	
	private List<Service> services;
 	private List<InterfaceType> interfaces;
 	private List<Schema> schemas;
 	private List<ComplexType> complexTypes;
 	private List<SimpleType> simpleTypes;
 	private String packageName;
 	private String wsdl;
 	
 	private String outputPath;
 	
 	public Wsdl2Java(){}
 	
 	public Wsdl2Java(String wsdl) throws WSDLException, MalformedURLException, IOException, URISyntaxException{
 		this.wsdl = wsdl;
		readAndInit(wsdl);
 	}
	
	public Wsdl2Java(String wsdl,String packageName) throws WSDLException, MalformedURLException, IOException, URISyntaxException{
		this(wsdl);
		this.packageName = packageName;
		buildArtifacts();
	}
	
	public void readAndInit(String wsdl) throws WSDLException, MalformedURLException, IOException, URISyntaxException{		
		this.wsdl = wsdl;
		WSDLReader reader = WSDLFactory.newInstance().newWSDLReader();
		this.description = reader.read(new URL(wsdl));
		initDocument();
	}
	
	public void setPackageName(String packageName) {
		this.packageName = packageName;
	}

	public void initDocument(){
		
		if(packageName==null){
			this.packageName = SDroidUtils.buildJavaPackageFromNamespace(description.getTargetNamespace());
		}
		
		this.services   = description.getServices();
		this.interfaces = description.getInterfaces();
		this.schemas    = description.getTypes().getSchemas();
		readTypes();
	}
	
	private void readTypes(){
		complexTypes = new ArrayList<ComplexType>();
		simpleTypes  = new ArrayList<SimpleType>();
		
		Map<QName, Type> typeMap = new HashMap<QName,Type>();
		
		for(Schema schema : schemas){
			
			for(Type type : schema.getTypes()){
				if(type.getQName()!=null && !typeMap.containsKey(type.getQName())){
					
					if(type instanceof ComplexType){
						ComplexType ct = (ComplexType) type;
						complexTypes.add(ct);
						typeMap.put(type.getQName(), type);
					}else if(type instanceof SimpleType){
						
						SimpleType st = (SimpleType) type;
						
						if(SDroidUtils.isEnum(st)){
							simpleTypes.add(st);
							typeMap.put(type.getQName(), type);
						}
					}
					
				}
			}
			
			for(Element element : schema.getElements()){
				
				Type type = element.getType();

				if(element.getQName()!=null && !typeMap.containsKey(element.getQName())){
			
					if(type instanceof ComplexType){
						ComplexType ct = (ComplexType) type;
						
						ct.setQName(element.getQName());
						
						complexTypes.add(ct);
						typeMap.put(element.getQName(), type);
					}else if(type instanceof SimpleType){
						
						SimpleType st = (SimpleType) type;
						
						st.setQName(element.getQName());
						
						if(SDroidUtils.isEnum(st)){
							simpleTypes.add(st);
							typeMap.put(element.getQName(), type);
						}
					}
					
				}
				
			}
			
			
			
		}
		
	}
	
	public void buildArtifacts() throws IOException{
		buildServices();
		buildPortTypes();
		buildComplexTypes();
		buildSimpleTypes();
	}
	
	public void buildServices() throws IOException{
		for(Service service : services){
			ServiceArtifactBuilder sab = new ServiceArtifactBuilder(service,packageName,wsdl);
			
			sab.toFile(outputPath);
		}
	}
	
	public void buildPortTypes() throws IOException{
		for(InterfaceType interfaceType : interfaces){
			PortTypeArtifactBuilder ptab = new PortTypeArtifactBuilder(interfaceType, packageName);
			//System.out.println(ptab.build());
			
			ptab.toFile(outputPath);
			
		}
	}
	
	public void buildComplexTypes() throws IOException{
		
		for(ComplexType ct : complexTypes){
			DTOArtifactBuilder dtoab = new DTOArtifactBuilder(ct, packageName);
			//System.out.println(dtoab.build());
			
			dtoab.toFile(outputPath);
		}
	}
	
	public void buildSimpleTypes() throws IOException{
		
		for(SimpleType st : simpleTypes){
			EnumerationArtifactBuilder eab = new EnumerationArtifactBuilder(st, packageName);
			//System.out.println(eab.build());
			eab.toFile(outputPath);
		}
	}

	public Description getDescription() {
		return description;
	}

	public List<Service> getServices() {
		return services;
	}

	public List<InterfaceType> getInterfaces() {
		return interfaces;
	}

	public List<Schema> getSchemas() {
		return schemas;
	}

	public List<ComplexType> getComplexTypes() {
		return complexTypes;
	}

	public String getPackageName() {
		return packageName;
	}

	public String getWsdl() {
		return wsdl;
	}

	public List<SimpleType> getSimpleTypes() {
		return simpleTypes;
	}

	public String getOutputPath() {
		return outputPath;
	}

	public void setOutputPath(String outputPath) {
		this.outputPath = outputPath;
	}
	
	
	
	/*
	public void buildComplexTypes(){
		
		
		for(Schema schema : schemas){
			
			for(Type type : schema.getTypes()){
				
				if(type instanceof ComplexType){
					ComplexType ct = (ComplexType) type;
					DTOArtifactBuilder dtoab = new DTOArtifactBuilder(ct, packageName);
					
					System.out.println(dtoab.build());
				}
				
			}
			
		}
	}
	
	*/

}
